﻿/*
  DISCLAIMER:
THIS CODE IS SAMPLE CODE. THESE SAMPLES ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
MICROSOFT FURTHER DISCLAIMS ALL IMPLIED WARRANTIES INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR OF FITNESS FOR
A PARTICULAR PURPOSE. THE ENTIRE RISK ARISING OUT OF THE USE OR PERFORMANCE OF THE SAMPLES REMAINS WITH YOU. IN NO EVENT SHALL
MICROSOFT OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THE
SAMPLES, EVEN IF MICROSOFT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION
OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY NOT APPLY TO YOU.
 * */

using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using Microsoft.Exchange.WebServices.Data;


namespace EWSPushListener
{
    public abstract class PushEvent
    {
        public EventType EventType;
        public FolderId OldParentFolderId;
        public FolderId ParentFolderId;
        public DateTime TimeStamp;

        public PushEvent()
        {
        }
    }

    public class PushFolderEvent : PushEvent
    {
        public FolderId FolderId;
        public FolderId OldFolderId;
        public Nullable<int> UnreadCount;

        public PushFolderEvent()
        {
        }

        public PushFolderEvent(
            FolderId folderId, 
            FolderId oldFolderId, 
            Nullable<int> unreadCount, 
            EventType eventType, 
            FolderId oldParentFolderId, 
            FolderId parentFolderId, 
            DateTime timeStamp)
        {
            this.EventType = eventType;
            this.OldParentFolderId = oldParentFolderId;
            this.ParentFolderId = parentFolderId;
            this.TimeStamp = timeStamp;

            this.FolderId = folderId;
            this.OldFolderId = oldFolderId;
            this.UnreadCount = unreadCount;
        }
    }

    public class PushItemEvent : PushEvent
    {
        public ItemId ItemId;
        public ItemId OldItemId;

        public PushItemEvent()
        {
        }
        
        public PushItemEvent(
            ItemId itemId,
            ItemId oldItemId,
            EventType eventType,
            FolderId oldParentFolderId,
            FolderId parentFolderId,
            DateTime timeStamp)

        {
            this.EventType = eventType;
            this.OldParentFolderId = oldParentFolderId;
            this.ParentFolderId = parentFolderId;
            this.TimeStamp = timeStamp;

            this.ItemId = itemId;
            this.OldItemId = oldItemId;
        }
    }

    public class EWSPushEvent : EventArgs
    {
        public string SubscriptionId;
        public string Watermark;
        public string EventName;
        public PushEvent NotificationEvent;


        public EWSPushEvent(string subscriptionId, BaseNotificationEventType eventType, string watermark)
        {
            SubscriptionId = subscriptionId;
            Watermark = watermark;

            if ((eventType is ModifiedEventType) || (eventType is BaseObjectChangedEventType))
            {
                BaseObjectChangedEventType evnt = eventType as BaseObjectChangedEventType;
                if (evnt.Item is FolderIdType)
                {
                    NotificationEvent = new PushFolderEvent();
                    (NotificationEvent as PushFolderEvent).FolderId = new FolderId((evnt.Item as FolderIdType).Id);
                }
                else
                {
                    NotificationEvent = new PushItemEvent();
                    (NotificationEvent as PushItemEvent).ItemId = new ItemId((evnt.Item as ItemIdType).Id);
                }
                NotificationEvent.EventType = EventType.Modified;
                NotificationEvent.ParentFolderId = new FolderId(evnt.ParentFolderId.Id);
                NotificationEvent.OldParentFolderId = null;
                NotificationEvent.TimeStamp = evnt.TimeStamp;
            }
            else if (eventType is MovedCopiedEventType)
            {
                MovedCopiedEventType evnt = eventType as MovedCopiedEventType;
                if (evnt.Item is FolderIdType)
                {
                    NotificationEvent = new PushFolderEvent();
                    (NotificationEvent as PushFolderEvent).FolderId = new FolderId((evnt.Item as FolderIdType).Id);
                }
                else
                {
                    NotificationEvent = new PushItemEvent();
                    (NotificationEvent as PushItemEvent).ItemId = new ItemId((evnt.Item as ItemIdType).Id);
                }
                if (eventType.GetType().ToString() == "MovedEvent")
                {
                    NotificationEvent.EventType = EventType.Moved;
                }
                else
                {
                    NotificationEvent.EventType = EventType.Copied;
                }
                NotificationEvent.ParentFolderId = new FolderId(evnt.ParentFolderId.Id);
                NotificationEvent.OldParentFolderId = new FolderId(evnt.OldParentFolderId.Id);
                NotificationEvent.TimeStamp = evnt.TimeStamp;
            }
            

            // Set base properties
            //NotificationEvent.ParentFolderId = "";
            //NotificationEvent.OldParentFolderId = "";
            if (!(NotificationEvent == null))
            {
                EventName = NotificationEvent.EventType.ToString();
            }
            else
            {
                EventName = "Status";
            }
        }

        private FolderId FolderIdTypeToFolderId(FolderIdType id)
        {
            FolderId folderId = new FolderId(id.Id);
            //folderId.ChangeKey = id.ChangeKey;
            return folderId;
        }
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public partial class Listener :  NotificationServicePortType
    {
        public event EventHandler EWSPushEvent;
        
        public Listener()
        {

        }

        NotificationType notification;
        string subscriptionId;
        string previousWatermark;

        
        public SendNotificationResponse SendNotification(SendNotificationRequest request)
        {
            
            SendNotificationResponse snr = new SendNotificationResponse();
            snr.SendNotificationResult = new SendNotificationResultType();

            ResponseMessageType[] rmta = request.SendNotification.ResponseMessages.Items;

            foreach (ResponseMessageType rmt in rmta)
            {
                if (rmt.ResponseCode != ResponseCodeType.NoError)
                {
                    // Stop the subscription if there is an error.
                    snr.SendNotificationResult.SubscriptionStatus = SubscriptionStatusType.Unsubscribe;
                    return snr;
                }

                SendNotificationResponseMessageType snrmt = rmt as SendNotificationResponseMessageType;
                notification = snrmt.Notification;
                subscriptionId = notification.SubscriptionId;
                previousWatermark = notification.PreviousWatermark;

                // Loop through the notifications
                for (int i=0; i<notification.Items.Length; i++)
                {
                    BaseNotificationEventType bnet = notification.Items[i];
                    
                    if (EWSPushEvent != null)
                    {

                        EWSPushEvent e = new EWSPushEvent(subscriptionId, bnet, previousWatermark);
                        
                        EWSPushEvent(this, e);
                    }
                }
            }

            snr.SendNotificationResult.SubscriptionStatus = SubscriptionStatusType.OK;
            return snr;
        }

    }
}
